// Buffer.cpp
#include "../include/buffer.h"

namespace net {

Buffer::Buffer(size_t initialSize)
    : _buffer(initialSize),
      _readIdx(0),
      _writeIdx(0) {}

void Buffer::ensureWriteSpace(size_t len) 
{
    // 情况1：末尾空闲空间⼤⼩⾜够，直接返回
    if (tailSize() >= len)
        return;

    // 情况2：末尾空闲空间不够，则判断加上起始位置的空闲空间大小是否足够
    //        够了就将数据移动到起始位置
    if (headSize() + tailSize() >= len) 
    {
        // 移动数据到缓冲区起始位置
        size_t readable = readAbleSize();
        std::copy(readPosition(), readPosition() + readable, begin());
        _readIdx = 0;
        _writeIdx = readable;
    } 
    else 
    {
        // 情况3：总体空间不够，则需要扩容
        // 不移动数据，直接给写偏移之后扩容足够空间即可
        _buffer.resize(_writeIdx + len);
    }
}

void Buffer::moveReadOffset(size_t len) 
{
    assert(len <= readAbleSize());
    _readIdx += len;
    if (_readIdx == _writeIdx) 
    {
        // 读写位置相遇，重置缓冲区
        clear();
    }
}

void Buffer::moveWriteOffset(size_t len) 
{
    assert(len <= tailSize());
    _writeIdx += len;
}

void Buffer::write(const void* data, size_t len) 
{
    if (len == 0) return;
    ensureWriteSpace(len);
    std::copy((const char*)data, (const char*)data + len, writePosition());
}

void Buffer::writeAndPush(const void* data, size_t len) 
{
    write(data, len);
    moveWriteOffset(len);
}

void Buffer::writeString(const std::string& data) 
{
    write(data.c_str(), data.size());
}

void Buffer::writeStringAndPush(const std::string& data) 
{
    writeString(data);
    moveWriteOffset(data.size());
}

void Buffer::writeBuffer(const Buffer& data) 
{
    write(data.readPosition(), data.readAbleSize());
}

void Buffer::writeBufferAndPush(const Buffer& data) 
{
    writeBuffer(data);
    moveWriteOffset(data.readAbleSize());
}

void Buffer::read(void* buff, size_t len) const 
{
    assert(len <= readAbleSize());
    std::copy(readPosition(), readPosition() + len, (char*)buff);
}

void Buffer::readAndPop(void* buff, size_t len) 
{
    read(buff, len);
    moveReadOffset(len);
}

std::string Buffer::readString(size_t len) const 
{
    assert(len <= readAbleSize());
    std::string result(readPosition(), len);
    return result;
}

std::string Buffer::readStringAndPop(size_t len) 
{
    std::string result = readString(len);
    moveReadOffset(len);
    return result;
}

char* Buffer::findCRLF() 
{
    const char* crlf = static_cast<const char*>(memchr(readPosition(), '\n', readAbleSize()));
    return const_cast<char*>(crlf);
}

const char* Buffer::findCRLF() const 
{
    return static_cast<const char*>(memchr(readPosition(), '\n', readAbleSize()));
}

std::string Buffer::getLine() const 
{
    const char* crlf = findCRLF();
    if (crlf) 
    {
        return readString(crlf - readPosition() + 1);
    }
    return "";
}

std::string Buffer::getLineAndPop() 
{
    std::string line = getLine();
    if (!line.empty()) 
    {
        moveReadOffset(line.size());
    }
    return line;
}

void Buffer::clear() 
{
    _readIdx = 0;
    _writeIdx = 0;
}

} // namespace net